package org.jeecg.modules.demo.Kingdee.Job;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.kingdee.bos.webapi.sdk.K3CloudApi;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.jeecg.modules.demo.DingTalk.MonthPayableOnoa.entity.MonthPayableOnoa;
import org.jeecg.modules.demo.DingTalk.MonthPayableOnoa.entity.MonthPayableOnoaItem;
import org.jeecg.modules.demo.DingTalk.MonthPayableOnoa.service.IMonthPayableOnoaService;
import org.jeecg.modules.demo.DingTalk.MonthPayableOnoa.service.IMonthPayableOnoaItemService;
import org.jeecg.modules.demo.Kingdee.bank.entity.settlement.SinglePaymentRequest;
import org.jeecg.modules.demo.Kingdee.bank.entity.settlement.SinglePaymentResponse;
import org.jeecg.modules.demo.util.SignUtil;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 处理月结付款单的定时任务类，用于发起单笔付款申请
 * 
 * 功能：
 * 1. 查询所有已审核但未付款的月结付款单
 * 2. 根据月结付款单编号获取金蝶单据中的结算组织字段
 * 3. 获取结算组织的默认银行账号
 * 4. 发起单笔付款申请
 * 5. 按每个供应商维度发起申请
 * 
 * 工作流程：
 * 1. 查询数据库中状态为"已审核"但付款状态不为"已付款"的记录
 * 2. 遍历每条记录，获取月结付款单编号
 * 3. 根据月结付款单编号查询金蝶单据，获取结算组织字段F_NHOV_OrgId_83g.FNumber
 * 4. 根据结算组织获取默认银行账号
 * 5. 按供应商维度汇总金额并发起单笔付款申请
 */
@Slf4j
@Component
public class ProcessMonthPayableForSinglePaymentJob implements Job {

    @Autowired
    private IMonthPayableOnoaService monthPayableOnoaService;

    @Autowired
    private IMonthPayableOnoaItemService monthPayableOnoaItemService;

    @Autowired
    private SignUtil signUtil;

    /**
     * 定时任务执行方法
     * 
     * @param jobExecutionContext 定时任务执行上下文
     * @throws Exception 执行过程中可能抛出的异常
     */
    @SneakyThrows
    @Override
    public void execute(JobExecutionContext jobExecutionContext) {
        try {
            log.info("开始执行月结付款单处理任务，发起单笔付款申请");

            // 查询数据库中状态为"已审核"但付款状态不为"已付款"的记录
            List<MonthPayableOnoa> pendingRecords = monthPayableOnoaService.list(
                new com.baomidou.mybatisplus.core.conditions.query.QueryWrapper<MonthPayableOnoa>()
                    .eq("status", "已审核")
                    .ne("pay_status", "已付款")
            );

            log.info("找到 {} 条待处理记录", pendingRecords.size());

            // 遍历每条记录
            int processedCount = 0;
            for (MonthPayableOnoa record : pendingRecords) {
                try {
                    String monthpayBillno = record.getMonthpayBillno();
                    if (monthpayBillno != null && !monthpayBillno.isEmpty()) {
                        log.info("开始处理月结付款单: {}", monthpayBillno);
                        
                        // 初始化金蝶API
                        K3CloudApi api = new K3CloudApi();
                        
                        // 根据月结付款单编号获取结算组织字段
                        String orgNumber = getOrganizationInfoByMonthpayBillno(monthpayBillno, api);
                        if (orgNumber == null) {
                            log.error("未能获取月结付款单 {} 的结算组织信息", monthpayBillno);
                            continue;
                        }
                        
                        // 获取结算组织的默认银行账号
                        String defaultBankAccount = getDefaultBankAccountByOrg(orgNumber, api);
                        if (defaultBankAccount == null) {
                            log.error("未能获取组织 {} 的默认银行账号", orgNumber);
                            continue;
                        }
                        
                        log.info("月结付款单 {} 对应的结算组织: {}, 默认银行账号: {}", 
                            monthpayBillno, orgNumber, defaultBankAccount);
                        
                        // 获取子表记录并按供应商维度处理
                        List<MonthPayableOnoaItem> items = monthPayableOnoaItemService.selectByMainId(record.getId());
                        if (items != null && !items.isEmpty()) {
                            // 不再需要按供应商汇总金额，因为子表中的供应商数据是唯一的
                            // 直接为每个供应商发起单笔付款申请
                            boolean allSuccess = true;
                            for (MonthPayableOnoaItem item : items) {
                                // 只对状态不为"付款中"和"已付款"的记录发起付款
                                String currentPayStatus = item.getPayStatus();
                                if ("付款中".equals(currentPayStatus) || "已付款".equals(currentPayStatus)) {
                                    log.info("子表记录 {} 的付款状态为 {}，跳过处理", item.getId(), currentPayStatus);
                                    continue;
                                }
                                
                                String supplierNo = item.getSupplierNo();
                                String supplierName = item.getSupplier();
                                String extno = item.getExtno();
                                BigDecimal amt = item.getAmt();
                                    
                                if (supplierNo != null && !supplierNo.isEmpty() && amt != null) {
                                    SupplierPaymentInfo info = new SupplierPaymentInfo(supplierNo, supplierName, amt);
                                    PaymentResult result = sendSinglePaymentRequest(extno, info, defaultBankAccount, orgNumber);
                                    if (result.success) {
                                        // 将外部流水号和付款结果反写到子表记录中
                                        item.setPayStatus("付款中");
                                        monthPayableOnoaItemService.updateById(item);
                                    } else {
                                        allSuccess = false;
                                        // 如果有错误信息，则将错误信息写入付款状态字段
                                        if (result.failreson != null && !result.failreson.isEmpty()) {
                                            item.setPayStatus(result.failreson);
                                        } else {
                                            item.setPayStatus("付款失败");
                                        }
                                        monthPayableOnoaItemService.updateById(item);
                                    }
                                } else {
                                    log.warn("子表记录 {} 的供应商信息不完整", item.getId());
                                    allSuccess = false;
                                    item.setPayStatus("信息不完整");
                                    monthPayableOnoaItemService.updateById(item);
                                }
                            }
                            
                            // 如果所有付款申请都成功发送，则更新付款状态
                            if (allSuccess) {
                                record.setPayStatus("付款中");
                                monthPayableOnoaService.updateById(record);
                                processedCount++;
                                log.info("月结付款单 {} 的所有付款申请已成功发送", monthpayBillno);
                            }
                        }
                    } else {
                        log.warn("记录 {} 的月结付款单编号为空", record.getId());
                    }
                } catch (Exception e) {
                    log.error("处理记录 {} 时发生错误: ", record.getId(), e);
                }
            }
            
            log.info("任务执行完成，共处理 {} 条记录", processedCount);
            
        } catch (Exception e) {
            log.error("执行月结付款单处理任务时发生错误: ", e);
        }
    }
    
    /**
     * 根据月结付款单编号查询金蝶单据，获取结算组织字段
     * 
     * @param monthpayBillno 月结付款单编号
     * @param api 金蝶API实例
     * @return 组织编码
     */
    private String getOrganizationInfoByMonthpayBillno(String monthpayBillno, K3CloudApi api) {
        try {
            // 构造查询条件，根据月结付款单编号查询
            String filterString = "FBillNo = '" + monthpayBillno + "'";
            String fieldKeys = "FID,FBillNo,F_NHOV_OrgId_83g.FNUMBER";
            
            // 构造查询JSON
            String queryJson = String.format(
                "{\"FormId\":\"NHOV_MONTH_PAYABLE\",\"FieldKeys\":\"%s\",\"FilterString\":\"%s\",\"OrderString\":\"\",\"TopRowCount\":0,\"StartRow\":0,\"Limit\":1}",
                fieldKeys, filterString
            );
            
            log.info("开始查询金蝶月结付款单，查询条件: {}", filterString);
            
            // 执行查询
            String resultStr = api.billQuery(queryJson);
            
            // 解析查询结果
            List<JSONObject> resultList = JSONArray.parseArray(resultStr, JSONObject.class);
            
            if (!resultList.isEmpty()) {
                JSONObject item = resultList.get(0);
                String orgNumber = item.getString("F_NHOV_OrgId_83g.FNUMBER");
                log.info("查询到月结付款单，编号: {}, 组织编码: {}", monthpayBillno, orgNumber);
                return orgNumber;
            } else {
                log.warn("未找到月结付款单编号 {} 对应的金蝶单据", monthpayBillno);
                return null;
            }
        } catch (Exception e) {
            log.error("根据月结付款单编号 {} 查询金蝶单据时发生错误: ", monthpayBillno, e);
            return null;
        }
    }
    
    /**
     * 根据组织编码获取默认银行账号
     * 
     * @param orgNumber 组织编码
     * @param api 金蝶API实例
     * @return 默认银行账号
     */
    private String getDefaultBankAccountByOrg(String orgNumber, K3CloudApi api) {
        try {
            if (orgNumber == null || orgNumber.isEmpty()) {
                log.warn("组织编码为空，无法查询默认银行账号");
                return null;
            }
            
            // 构造查询条件，根据组织编码和默认银行账号标识查询银行账号
            String filterString = "FISDEFAULTBANK ='1' AND FUseOrgId.FNumber = '" + orgNumber + "'";
            String fieldKeys = "FName,FNumber";
            
            // 构造查询JSON
            String queryJson = String.format(
                "{\"FormId\":\"CN_BANKACNT\",\"FieldKeys\":\"%s\",\"FilterString\":\"%s\",\"OrderString\":\"\",\"TopRowCount\":0,\"StartRow\":0,\"Limit\":1}",
                fieldKeys, filterString
            );
            
            log.info("开始查询默认银行账号，查询条件: {}", filterString);
            
            // 执行查询
            String resultStr = api.billQuery(queryJson);
            
            // 解析查询结果
            List<JSONObject> resultList = JSONArray.parseArray(resultStr, JSONObject.class);
            
            if (!resultList.isEmpty()) {
                JSONObject item = resultList.get(0);
                String bankAccount = item.getString("FNumber");
                log.info("查询到组织 {} 的默认银行账号: {}", orgNumber, bankAccount);
                return bankAccount;
            } else {
                log.warn("未找到组织 {} 的默认银行账号", orgNumber);
                return null;
            }
        } catch (Exception e) {
            log.error("查询组织 {} 的默认银行账号时发生错误: ", orgNumber, e);
            return null;
        }
    }
    
    /**
     * 发起单笔付款申请
     * 
     * @param extno 外部流水号
     * @param supplierInfo 供应商付款信息
     * @param defaultBankAccount 默认银行账号
     * @param orgNumber 组织编码
     * @return 是否成功发送付款申请
     */
    private PaymentResult sendSinglePaymentRequest(String extno, SupplierPaymentInfo supplierInfo,
                                          String defaultBankAccount, String orgNumber) {
        try {
            // 获取供应商银行信息
            K3CloudApi api = new K3CloudApi();
            JSONObject supplierBankInfo = getSupplierBankInfo(supplierInfo.supplierNo, api);
            if (supplierBankInfo == null) {
                log.error("未能获取供应商 {} 的银行信息", supplierInfo.supplierName);
                return new PaymentResult(false, extno,"未能获取供应商"+supplierInfo.supplierName+"的银行信息");
            }
            
            // 构造单笔付款请求
            SinglePaymentRequest request = new SinglePaymentRequest();
            
            // 设置付款方信息
            request.setPypartyAccnum(defaultBankAccount); // 付款方账号为结算组织的默认银行账号
            
            // 设置收款方信息
            request.setRcvpyAccnum(supplierBankInfo.getString("FBankCode")); // 收款方账号
            request.setRcvpyAccnm(supplierBankInfo.getString("FBankHolder")); // 收款方户名
            request.setRcvpartyDepbnkId(supplierBankInfo.getString("FOpenBankName")); // 收款方开户行
            
            // 设置交易信息
            request.setAmt(supplierInfo.amount); // 付款金额
            
            // 设置外部请求流水号（使用子表表中的外部流水号）
            request.setExternalNum(extno);
            
            // 设置附言
            request.setPscpt("月结付款-" + supplierInfo.supplierName);
            request.setRmrk("月结付款-" + supplierInfo.supplierName);
            request.setCurrencyID("CNY");
            request.setPyAccTp("00");

            // 添加时间戳参数
            String timestamp = String.valueOf(System.currentTimeMillis());
            
            // 构造包含签名和时间戳的请求体
            Map<String, Object> requestBodyMap = new HashMap<>();
            // 只放入上方request设置了的值
            requestBodyMap.put("externalNum", request.getExternalNum());
            requestBodyMap.put("pypartyAccnum", request.getPypartyAccnum());
            requestBodyMap.put("rcvpyAccnum", request.getRcvpyAccnum());
            requestBodyMap.put("rcvpyAccnm", request.getRcvpyAccnm());
            requestBodyMap.put("rcvpartyDepbnkId", request.getRcvpartyDepbnkId());
            requestBodyMap.put("pyAccTp", request.getPyAccTp());
            // 确保金额格式化为两位小数
            requestBodyMap.put("amt", String.format("%.2f", request.getAmt()));
            requestBodyMap.put("currencyID", request.getCurrencyID());
            requestBodyMap.put("pscpt", request.getPscpt());
            requestBodyMap.put("rmrk", request.getRmrk());
            requestBodyMap.put("timestamp", timestamp);
            requestBodyMap.put("userName", "ZHJTSJ003-ZL");

            // 生成签名
            String sign = signUtil.generateSign(requestBodyMap);
            requestBodyMap.put("sign", sign);
            
            String requestBodyJson = JSON.toJSONString(requestBodyMap);
            
            // 发送HTTP请求到银行接口
            try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
                HttpPost httpPost = new HttpPost("http://localhost:8080/api/bank/settlement/single-payment/apply");
                httpPost.setHeader("Content-Type", "application/json");
                httpPost.setEntity(new StringEntity(requestBodyJson, "UTF-8"));
                
                log.info("发送单笔付款申请，URL: {}, 请求参数: {}", 
                    "http://localhost:8080/api/bank/settlement/single-payment/apply", requestBodyJson);
                
                try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
                    String responseBody = EntityUtils.toString(response.getEntity());
                    int statusCode = response.getStatusLine().getStatusCode();
                    
                    if (statusCode >= 200 && statusCode < 300) {
                        SinglePaymentResponse paymentResponse = JSON.parseObject(responseBody, SinglePaymentResponse.class);
                        if (paymentResponse != null) {
                            log.info("单笔付款申请发送成功: status={}, statusText={}, externalNum={},失败原因={}",
                                paymentResponse.getStatus(), 
                                paymentResponse.getStatusText(), 
                                paymentResponse.getExternalNum(),
                                paymentResponse.getFailReason()
                            );
                            
                            // 检查响应中是否有错误信息
                            if ("ERROR".equals(paymentResponse.getStatus())) {
                                // 如果状态不是"0"，表示有错误，将错误原因写入子表的付款状态字段
                                String failReason = paymentResponse.getFailReason();
                                if (failReason != null && !failReason.isEmpty()) {
                                    return new PaymentResult(false, paymentResponse.getExternalNum(), failReason);
                                } else {
                                    return new PaymentResult(false, paymentResponse.getExternalNum(), paymentResponse.getStatusText());
                                }
                            }
                            
                            // 状态为0表示成功
                            return new PaymentResult(true, paymentResponse.getExternalNum(), null);
                        }
                    } else {
                        log.error("单笔付款申请发送失败，HTTP状态码: {}，响应内容: {}", statusCode, responseBody);
                        return new PaymentResult(false, extno, "HTTP请求失败，状态码: " + statusCode);
                    }
                }
            }
        } catch (Exception e) {
            log.error("发送供应商 {} 的单笔付款申请时发生错误: ", supplierInfo.supplierName, e);
            return new PaymentResult(false, extno,"系统错误");
        }
        
        return new PaymentResult(false, extno,"系统错误");
    }
    
    /**
     * 根据供应商编号获取供应商银行信息
     * 
     * @param supplierNo 供应商编号
     * @param api 金蝶API实例
     * @return 供应商银行信息
     */
    private JSONObject getSupplierBankInfo(String supplierNo, K3CloudApi api) {
        try {
            // 构造查询条件
            String filterString = "FNumber = '" + supplierNo + "'";
            String fieldKeys = "FOpenBankName,FBankCode,FBankHolder";
            
            // 构造查询JSON
            String queryJson = String.format(
                "{\"FormId\":\"BD_Supplier\",\"FieldKeys\":\"%s\",\"FilterString\":\"%s\",\"OrderString\":\"\",\"TopRowCount\":0,\"StartRow\":0,\"Limit\":1}",
                fieldKeys, filterString
            );
            
            log.info("开始查询供应商银行信息，查询条件: {}", filterString);
            
            // 执行查询
            String resultStr = api.billQuery(queryJson);
            
            // 解析查询结果
            List<JSONObject> resultList = JSONArray.parseArray(resultStr, JSONObject.class);
            
            if (!resultList.isEmpty()) {
                JSONObject item = resultList.get(0);
                log.info("查询到供应商 {} 的银行信息", supplierNo);
                return item;
            } else {
                log.warn("未找到供应商 {} 的银行信息", supplierNo);
                return null;
            }
        } catch (Exception e) {
            log.error("查询供应商 {} 的银行信息时发生错误: ", supplierNo, e);
            return null;
        }
    }
    
    /**
     * 供应商付款信息内部类
     */
    private static class SupplierPaymentInfo {
        private String supplierNo;
        private String supplierName;
        private BigDecimal amount;
        
        public SupplierPaymentInfo(String supplierNo, String supplierName, BigDecimal amount) {
            this.supplierNo = supplierNo;
            this.supplierName = supplierName;
            this.amount = amount;
        }
    }
    
    /**
     * 付款结果内部类
     */
    private static class PaymentResult {
        private boolean success;
        private String externalNum;
        private String failreson;

        public PaymentResult(boolean success, String externalNum, String failreson) {
            this.success = success;
            this.externalNum = externalNum;
            this.failreson = failreson;
        }
    }
}